@OPTIONS
locals


@main[]
	^dshow[начало]
	^use[Sys.p]
	^use[Class.p]
	^use[Many.p]
	^use[ActiveRecord.p]
	
	^dshow[подключил Vendor-классы]
	
	^use[MySql.p]
	
	^rem{ ^Profiler:do[Many;ActiveRecord] }
	
	^dshow[подключил MySql.p]
	
	$MAIN:oSql[^MySql::create[$MAIN:SQL.connect-string;
		$.bDebug(1)
		$.dCacheInterval(0)
		$.sCacheDir[/../data/cache/sql]
	]]
	
	$MAIN:time_2_begin($status:rusage.tv_sec+$status:rusage.tv_usec/1000000)
	^MAIN:oSql.server{
#	^connect[$MAIN:SQL.connect-string]{
		$MAIN:time_2_end($status:rusage.tv_sec+$status:rusage.tv_usec/1000000)
		$result[^niam[]]
	}


@niam[]
	^rem{
		Добавляю пару стандартных методов в клиентский код
		Это нужно повторить для каждого наследника ActiveRecord
	}
	^useAndExpandClass[Exhibit]
	^useAndExpandClass[Calendar]
	^useAndExpandClass[Picture]
	^useAndExpandClass[File]
 	^rem{ 41 ms, 550 KB }
 	^rem{ простой ^use[] - 39 ms и 500 KB }
	
	$ActiveRecord:hC.Exhibit[^hash::create[]]
	$ActiveRecord:hC.Calendar[^hash::create[]]
	$ActiveRecord:hC.Picture[^hash::create[]]
	$ActiveRecord:hC.File[^hash::create[]]
 	
	
	^rem{ имя контроллера, который вызывается по умолчанию }
	$sIndexController[collections]
	
	^rem{ разборки с URL }
	$sUri[^request:uri.match[\?.*][]{}]	
	^sUri.match[^^/(\w+)?/?(\w+)?/?(.*)][]{
		
		^rem{ пробуем создать контроллер с именем из первого параметра }
		$oController[^createController[$match.1;$match.2;$match.3;^request:uri.match[[^^?]*\??(.*)?][]{$match.1};$request:query]]

		^rem{ если контроллер создать не удалось - пробуем создать контроллер по умолчанию, а первый параметр присвоить имени действия }
		^if(!def $oController){
			$oController[^createController[$sIndexController;$match.1;^if(def $match.2 && def $match.3){${match.2}/${match.3}}{${match.2}${match.3}};^request:uri.match[[^^?]*\??(.*)?][]{$match.1};$request:query]]
		}
		
		^if(!def $oController){
			^throw[controller_not_found;createController;Контроллер «${match.1}» не существует или не может быть подключен.]
		}
	}

	^rem{ вызывается действие. Вынесено сюда, чтобы контролировать исключения в одном месте }
	^try{
		^rem{ в mContent будет string или xdoc }
		$mContent[^oController.action[]]
	}{
		^if($exception.type eq action_not_found){
			$exception.handled(true)
			^throw[action_not_found;action;Действие «${oController.h0.sAction}» не определено в контроллере ${oController.CLASS_NAME}.]
		}
	}
	
	^rem{ отладочный вывод или чистовой с применением шаблона }
	^switch[$form:mode]{
		^case[xml]{
			^rem{ выключено кеширование. Вывод итогового XML-документа. }
			$response:expires[^date::now(-1)]
			$response:Pragma[no-cache]
			$response:Cache-Control[private,no-cache,no-store]
			^use[ixColorer.p]
			^prepareFormat[$mContent]
			$result[^taint[html][^mContent.string[$.method[xml]$.indent[yes]]]]
			^rem{ подсветка синтаксиса xml }
			$pColor[^ixColorer::create[$result]]
			$result[^pColor.getString[]]
			$result[<html><head><link rel="stylesheet" type="text/css" href="/css/highlighting.css" /></head>
							<body>^result.match[(^^|(?<=\s{2}))\s{2}][gm]{<kbd>&nbsp^;&nbsp^;&nbsp^;&nbsp^;</kbd>}</body></html>]
		}
		^case[nox]{
			^if($mContent is xdoc){
				$result[^transform[$mContent;${oController.h0.sController};${oController.h0.sAction};nox]]
			}{
				$result[$mContent]
			}
		}
		^case[DEFAULT]{
			^if($mContent is xdoc){
				$result[^transform[$mContent;${oController.h0.sController};${oController.h0.sAction}]]
			}{
				$result[$mContent]
			}
		}
	}


# хотите немного программистской магии?
@transform[xContent;sControllerName;sAction;sMode]
	^rem{ создается супершаблон, в который инклюдятся общий шаблон контроллера и шаблон действия }
	^rem{ TODO: parser://метод/параметр ??? }
	$xTemplate[^xdoc::create[/../data/app/views/]{<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE document SYSTEM "http://localhost/symbols.ent">
	<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
		<xsl:include href="layouts/^sControllerName.lower[].xsl" />
		<xsl:include href="^sControllerName.lower[]/${sAction}.xsl" />
	</xsl:stylesheet>}]
	
# 	$xFormConnector[^xdoc::create[/../data/app/views/layouts/]{<?xml version="1.0" encoding="UTF-8"?>
# 	<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
# 		<xsl:include href="XForms.xsl" />
# 		<xsl:template match="/" >
# 			<xsl:apply-templates select="form" mode="f_form" />
# 		</xsl:template>
# 	</xsl:stylesheet>}]
	
	^rem{ Если в директории с именем контроллера есть файл с именем действия, то вывод идет через него. }
	^rem{ а если он еще и xsl, то происходит трансформация }
	$sViewPath[/../data/app/views/^sControllerName.lower[]/]
	$sLayoutsPath[/../data/app/views/layouts/]
	^if(-d $sViewPath){
		^if(-f "$sViewPath/${sAction}.xsl"){
			^rem{ преобразование основным шаблоном }
			$transformedDoc[^xContent.transform[$xTemplate][
				$.nya[Параметр]
			]]
			
			^rem{ вывод в html }
			^prepareFormat[$transformedDoc]
			$result[^transformedDoc.string[
				$.method[xml]
			]]
			
			^rem{ вытаскивается html формы и трансформируется шаблоном XForms }
			^rem{ для форм, которые описаны по стандарту XForms, заведен специальный тег XForm }
			^rem{ страница может содержать обычные формы и они не будут преобразованы }
# 			^if($sMode ne nox){
# 				$result[^result.match[<XForm(.*?)</XForm>][g]{
# 					$xForm[^xdoc::create{<?xml version="1.0" encoding="UTF-8"?><form$match.1</form>}]
# 					$xForm[^xForm.transform[$xFormConnector]]
# 					^xForm.string[$.method[html]]
# 				}]
# 			}

		}
	}
	


# убирает пустые текстовые ноды (чтобы indent работал)
@prepareFormat[document]
	$rootnodes[$document.documentElement.childNodes]
	^prepareFormatChild[$document.documentElement;$rootnodes]


@prepareFormatChild[parent;child]
	^for[i](0;$child-1){
		$node[$child.$i]
		^if(($node.nodeType == $xdoc:TEXT_NODE) && ^node.nodeValue.trim[] eq ""){
			$node[^parent.removeChild[$node]]
		}{
			^if($node.nodeType==$xdoc:ELEMENT_NODE){
				^prepareFormatChild[$node;$node.childNodes]
			}
		}
	}


# пытается создать контроллерна основе нотформатированного имени
@createController[sName;sAction;sPath;sUri;sQuery]

	$sControllerName[^sName.match[^^(\w)(.*)][]{^match.1.upper[]^match.2.lower[]}]
	^if(!def $sAction){$sAction[index]}
	^try{
		^rem{ создается объект контроллера.
			  фабрику лень таскать за контроллерами, поэтому вот так.
			  в параметрах конструктора можно только строки передавать. }
		$sClassFileName[^sName.lower[].p]
		^try{
			^use[$sClassFileName]
		}{
			$exception.handled(true)
			^throw[class_file_not_found]
		}
		$result[^process{
			^^${sControllerName}Controller::init[]
			^$${sControllerName}Controller:h0[
				^$.sController[$sControllerName]
				^$.sAction[$sAction]
				^$.sPath[$sPath]
				^$.sUri[$sUri]
				^$.sQuery[$sQuery]
			]
		}]
	}{
		^if($exception.type eq class_file_not_found){
			$exception.handled(true)
			$result[]
		}
	}


# мегакруть
@useAndExpandClass[sClassName]
	^use[^sClassName.lower[].p]
	^rem{ статический метод. нужно переопределить во всех классах, чтобы можно было отловить caller.CLASS_NAME внутри метода. }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@find_all[sConditions]^#0A^^BASE:find_all[^$sConditions]}
	^rem{ статический метод. нужно переопределить во всех классах, чтобы можно было отловить caller.CLASS_NAME внутри метода. }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@find_slave[]^#0A^^BASE:find_slave[]}
	^rem{ конструктор, которому передается хеш параметров из БД }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@o_O[h]^#0A^$result[^^${sClassName}::init[^$h]]}
	^rem{ конструктор, которому передается хеш параметров из формы (с вложениями) }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@fromForm[h]^#0A^$result[^^${sClassName}::from_form[^$h]]}
	^process[$ActiveRecord:hO.$sClassName.cClass]{@from_form[h]^#0A^^BASE:from_form[^$h]}

	
	^rem{ статический метод, возвращающий пустой объект }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@initEmpty[]^#0A^$result[^^${sClassName}::emptyConstructor[]]}
	^rem{ пустой конструктор }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@emptyConstructor[]^#0A^^BASE:emptyConstructor[]}
	^rem{ GET_DEFAULT. должен доставать объект по id из хеша объектов... }
	^process[$ActiveRecord:hO.$sClassName.cClass]{@GET_DEFAULT[sName]
		^^if(^$id > 0){
			^^if(^$sName eq id){
				^^throw[no_id^;^;id объекта класса ^$CLASS_NAME неизвестен]
			}
	 		^^dshow[запросили ^$sName из ^$CLASS_NAME (^$id)]
			^$result[^$ActiveRecord:hC.^$CLASS_NAME.^$id.^$sName]
		}}
		
		